package org.nxl.ExceptionDetector;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class Consumer implements Runnable{
	
	private String dbPath;
	private BlockingQueue<Map> queue;
	private volatile int status = 0;
	
	
	public Consumer(String dbPath, BlockingQueue<Map> queue) {
		this.dbPath = dbPath;
		this.queue = queue;
		try {
		Connection conn = DriverManager.getConnection("jdbc:sqlite:"+dbPath);
        Statement stat = conn.createStatement();
        
        stat.executeUpdate("create table if not exists exceptions(app varchar(20),exception varchar(100), code varchar(200), num int, day char(8));");// 创建一个表，两列
        
        conn.close();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public void run() {
		consume();
	}
	
	public void consume() {
		Map map = null;
		List<Map> list = new ArrayList<Map>();
		long startTime = System.currentTimeMillis();
		while(true) {
			if(status == 1) {
				break;
			}
			try {
				map = queue.take();
			} catch (InterruptedException e) {
				break;
			}
			//System.out.println(map);
			if(map != null) {
				list.add(map);
			}
			
			if(System.currentTimeMillis() - startTime > 20000 || list.size() > 100) {
				insertIntoDB(list);
				startTime = System.currentTimeMillis();
				list = new ArrayList<Map>();
			}
		}
	}
	public void stop() {
		status = 1;
	}

	public void insertIntoDB(List<Map> list) {
		List<Map> reducedResult = reduce(list);
		try {
		Connection conn = DriverManager.getConnection("jdbc:sqlite:" + dbPath);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String day = sdf.format(new Date());
		for(Map m : reducedResult) {		
	        Statement stat = conn.createStatement();
	        String querySql = "select * from exceptions where app=\"" + m.get("app") + "\" and exception=\"" + m.get("exception") + "\" and code=\"" + m.get("code") + "\" and day = \"" + day + "\"";
	        String updateSql = "update exceptions set num = num + " + m.get("count") + " where app=\"" + m.get("app") + "\" and exception=\"" + m.get("exception") + "\" and code=\"" + m.get("code") +  "\" and day = \"" + day + "\"";
	        String insertSql = "insert into exceptions values(\"" + m.get("app") + "\",\"" + m.get("exception") +  "\",\"" + m.get("code") + "\"," + m.get("count")  + ",\"" + day + "\")";
	        //System.out.println(querySql);
	        ResultSet rs = stat.executeQuery(querySql);
	        if(rs.next()) {
	        	 //System.out.println(updateSql);
	        	stat.execute(updateSql);
	        } else {
	        	 //System.out.println(insertSql);
	        	stat.executeUpdate(insertSql);
	        }
		}
		} catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	public static List<Map> reduce(List<Map> list) {
		//System.out.println(list);
		//JSONArray a = new JSONArray();
		//a.addAll(list);
		//System.out.println(a.toJSONString());
		Collections.sort(list, new Comparator<Map>() {

			public int compare(Map o1, Map o2) {
				String app1 = (String) o1.get("app");
				String exception1 = (String) o1.get("exception");
				String code1 = (String)o1.get("code");
				
				String app2 = (String) o2.get("app");
				String exception2 = (String) o2.get("exception");
				String code2 = (String)o2.get("code");		
				return (app1+"|"+exception1+"|"+code1).compareTo(app2+"|"+exception2+"|"+code2);
			}
		});
		//System.out.println("after sort");
		//System.out.println(list);
		List<Map> result = new ArrayList<Map>();
		for(int i = 0; i < list.size(); i++) {
			Map m1 = list.get(i);
			int count = 1;
			int j = i+1;
			for(; j < list.size(); j++) {
				Map m2 = list.get(j);
				if(sameException(m1,m2)) {
					count++;
				} else {
					m1.put("count", count);
					result.add(m1);
					i = j-1;
					break;
				}
			}
			if(j == list.size()) {
				m1.put("count", count);
				result.add(m1);
				break;
			}
		}
		//System.out.println(result);
		return result;
		
	}
	public static boolean sameException(Map o1, Map o2) {
		String app1 = (String) o1.get("app");
		String exception1 = (String) o1.get("exception");
		String code1 = (String)o1.get("code");
		String app2 = (String) o2.get("app");
		String exception2 = (String) o2.get("exception");
		String code2 = (String)o2.get("code");	
		if(app1.equals(app2) && exception1.equals(exception2) && code1.equals(code2)) {
			return true;
		}
		return false;
	}
	public static void main(String[] args) {
		String x = null; //"[{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"}]";
		//"[{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:35)"},{"app":"app1","exception":"java.lang.NullPointerException","code":"arthas_test.Test.main(Test.java:26)"}]";
		
		JSONArray o = JSONArray.parseArray(x);
		
		List<Map> list = o.toJavaList(Map.class);
		
		List<Map> list1 = reduce(list);
		
		System.out.println(list1);

	}
}
